package org.rency.common.memcache.service.impl;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.rency.common.memcache.bean.MemcacheNode;
import org.rency.common.memcache.core.MemcachedClientFactory;
import org.rency.common.memcache.repository.NodeRepository;
import org.rency.common.memcache.service.MemcachedService;
import org.rency.common.memcache.support.annotation.MCacheDomain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.rubyeye.xmemcached.CASOperation;

public class MemcachedServiceImpl implements MemcachedService{
	
	private final Logger logger = LoggerFactory.getLogger(MemcachedServiceImpl.class);
	
	@Resource(name="memcachedClientFactory")
	private MemcachedClientFactory memcachedClientFactory;
	
	@Resource(name="nodeRepository")
	private NodeRepository nodeRepository;

	@Override
	public void addNode(MemcacheNode node) throws Exception {
		logger.info("add memcache node [{}].",node);
		memcachedClientFactory.getClient().addServer(node.getNodeHost(), node.getNodePort(), node.getNodeWeight());
		nodeRepository.save(node);
	}

	@Override
	public void removeNode(MemcacheNode node) throws Exception {
		logger.info("remove memcache node [{}].",node);
		memcachedClientFactory.getClient().removeServer(node.getNodeHost()+":"+node.getNodePort());
		nodeRepository.delete(node.getId());
	}
	
	@Override
	public Map<InetSocketAddress, Map<String, String>> getStatistics() throws Exception {
		logger.debug("get memcache statictis info.");
		return memcachedClientFactory.getClient().getStats();
	}

	@Override
	public Map<InetSocketAddress, Map<String, String>> getStatisticsByItem(String item) throws Exception{
		logger.debug("get memcache statictis info [{}].",item);
		return memcachedClientFactory.getClient().getStatsByItem(item);
	}

	@Override
	public boolean addData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().add(domain.getCacheKey(), domain.getExpireTime(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("add memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return false;
	}
	
	@Override
	public boolean setData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().set(domain.getCacheKey(), domain.getExpireTime(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("set memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return false;
	}

	@Override
	public Object getData(MCacheDomain domain) {
		Object result = null;
		try {
			return memcachedClientFactory.getClient().get(domain.getCacheKey());
		} catch (Exception e) {
			logger.error("get memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return result;
	}

	@Override
	public boolean updateData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().cas(domain.getCacheKey(), new CASOperation<Integer>() {
				@Override
				public int getMaxTries() {
					return 3;
				}
				@Override
				public Integer getNewValue(long currentCAS, Integer currentValue) {
					return currentValue;
				}
			});
		} catch (Exception e) {
			logger.error("update memcahce cache data[{}] error with retry 3 times.",domain.getCacheKey(),e);
		}
		return false;
	}

	@Override
	public boolean deleteData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().delete(domain.getCacheKey());
		} catch (Exception e) {
			logger.error("delete memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return false;
	}
	
	@Override
	public void deleteDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().deleteWithNoReply(domain.getCacheKey());
		} catch (Exception e) {
			logger.error("delete with no reply memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
	}

	@Override
	public boolean updateExpire(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().cas(domain.getCacheKey(), domain.getExpireTime(), new CASOperation<Integer>() {
				@Override
				public int getMaxTries() {
					return 3;
				}

				@Override
				public Integer getNewValue(long currentCAS, Integer currentValue) {
					return currentValue;
				}
			});
		} catch (Exception e) {
			logger.error("update expire memcahce cache data[{}] error with retry 3 times.",domain.getCacheKey(),e);
		}
		return false;
	}

	@Override
	public List<MemcacheNode> getAvailableServers() {
		try {
			List<MemcacheNode> nodes = new ArrayList<MemcacheNode>();
			Collection<InetSocketAddress> servers = memcachedClientFactory.getClient().getAvailableServers();
			for(InetSocketAddress isa : servers){
				MemcacheNode node = new MemcacheNode();
				node.setNodeHost(isa.getAddress().getHostAddress());
				node.setNodePort(isa.getPort());
				nodes.add(node);
			}
			return nodes;
		} catch (Exception e) {
			logger.error("get memcahce cache available server error.",e);
			return null;
		}
	}

	@Override
	public boolean replaceData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().replace(domain.getCacheKey(), domain.getExpireTime(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("replace memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return false;
	}

	@Override
	public boolean appendData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().append(domain.getCacheKey(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("append memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return false;
	}

	@Override
	public boolean prependData(MCacheDomain domain) {
		try {
			return memcachedClientFactory.getClient().prepend(domain.getCacheKey(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("prepend memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
		return false;
	}

	@Override
	public void addDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().addWithNoReply(domain.getCacheKey(), domain.getExpireTime(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("add with no reply memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
	}

	@Override
	public void setDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().setWithNoReply(domain.getCacheKey(), domain.getExpireTime(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("set with no reply memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
	}

	@Override
	public void updateDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().casWithNoReply(domain.getCacheKey(), new CASOperation<Integer>() {
				@Override
				public int getMaxTries() {
					return 3;
				}
				@Override
				public Integer getNewValue(long currentCAS, Integer currentValue) {
					return currentValue;
				}
			});
		} catch (Exception e) {
			logger.error("update with no reply memcahce cache data[{}] error with retry 3 times.",domain.getCacheKey(),e);
		}
	}

	@Override
	public void updateExpireWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().casWithNoReply(domain.getCacheKey(), domain.getExpireTime(), new CASOperation<Integer>() {
				@Override
				public int getMaxTries() {
					return 3;
				}

				@Override
				public Integer getNewValue(long currentCAS, Integer currentValue) {
					return currentValue;
				}
			});
		} catch (Exception e) {
			logger.error("update expire with no reply memcahce cache data[{}] error with retry 3 times.",domain.getCacheKey(),e);
		}
	}

	@Override
	public void replaceDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().replaceWithNoReply(domain.getCacheKey(), domain.getExpireTime(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("replace with no replay memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
	}

	@Override
	public void appendDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().appendWithNoReply(domain.getCacheKey(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("append with no reply with no replay memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
	}

	@Override
	public void prependDataWithNoReply(MCacheDomain domain) {
		try {
			memcachedClientFactory.getClient().prependWithNoReply(domain.getCacheKey(), domain.getCacheData());
		} catch (Exception e) {
			logger.error("prepend with no reply with no replay memcahce cache data[{}] error.",domain.getCacheKey(),e);
		}
	}
	
}